package com.example.demo.aspect;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.demo.annotation.RedisCache;
import com.example.demo.common.enums.StaticValues;
import com.example.demo.common.handler.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.Args;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ak
 * @date 2020/4/5 20:19
 * @description 用redis配合AOP和注解做缓存测试
 */
@Aspect
@Component
@Slf4j
public class RedisAspect {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private Object cacheResult;

    @Pointcut("@annotation(com.example.demo.annotation.RedisCache)")
    public void pointMethod() {
    }

    @Around("pointMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws CustomException {
        log.info("-----------开始环绕通知----------");
        try {
            //获取redisCache注解
            RedisCache redisCache = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(RedisCache.class);
            String key = getKey(joinPoint);
            cacheResult = redisTemplate.opsForValue().get(key);
            if (cacheResult == null) {
                //执行目标方法
                Object proceedResult = joinPoint.proceed();
                if (proceedResult != null) {
                    //将数据库结构的值存入缓存
                    if (redisCache.expired() > 0) {
                        //判断是否有自定义key
                        if (!StringUtils.isBlank(redisCache.redisKey())) {
                            key = redisCache.redisKey();
                        }
                        redisTemplate.opsForValue().set(key, proceedResult, redisCache.expired(), TimeUnit.SECONDS);
                    } else {
                        redisTemplate.opsForValue().set(key, proceedResult);
                    }
                }
            }
            log.info("查询缓存");
            return cacheResult;
        } catch (Throwable throwable) {
            log.error("缓存失败");
            throw new CustomException("缓存失败", 500);
        }
    }

    @Before("pointMethod()")
    public void doBefore() {
    }

    @After("pointMethod()")
    public void doAfterTom() {
    }

    @AfterReturning("pointMethod()")
    public void doAfterReturn() {
    }

    @AfterThrowing("pointMethod()")
    public void doAfterThrowTom() {
    }

    /**
     * key生成策略
     */
    private String getKey(ProceedingJoinPoint joinPoint) {
        //获取全类名
        String className = joinPoint.getTarget().toString().split("@")[0];
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取参数名
        Object[] args = joinPoint.getArgs();
        StringBuilder argId = new StringBuilder();
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length - 1; i++) {
                argId.append(args[i]);
            }
        }
        log.debug("key的名称为: {}", argId);
        return className + methodName + argId;
    }

}
